package datenverwaltung;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Desktop;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JProgressBar;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.util.URIUtil;
import org.jdesktop.xswingx.PromptSupport;

import com.main.meldungsverwaltung.GUI;
import com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException;

/**
 * Löscht bei Lösch-Action den Tracker und seine Meldungen. Bei Erstell-Action
 * wird ein neuer Tracker erstellt und das Tracker-Attribut entsprechend mit dem
 * neuen Tracker gesetzt.
 * 
 * @author felix
 * 
 */
public class TrackerVerwaltenThread extends Thread implements DBVerbindung {

	private final TrackerVerwaltungAction action;
	private JProgressBar progressBar;
	private String id;
	private Connection connection;
	private Tracker tracker;
	private JFrame container;
	private Map<String, Tracker> trackerListe;
	private JDialog dialog;
	private static final String EMAIL_SUBJECT = "Registrierung als Trucker bei Radio2000";

	/**
	 * Zum Löschen eines Trackers muss seine Tracker-ID übergeben werden. Beim
	 * Erstellen eines Trackers kann für die Tracker-ID null übergeben werden.
	 * Beim Eintragen eines Trackers muss die eingegebene ID hingegen wieder
	 * übergeben werden.
	 * 
	 * @param action
	 * @param progressBar
	 * @param id
	 * @param container
	 *            Container für den Dialog, der erzeugt wird
	 */
	public TrackerVerwaltenThread(TrackerVerwaltungAction action,
			JProgressBar progressBar, String id, JFrame container) {
		super();
		this.action = action;
		this.progressBar = progressBar;
		this.id = id;
		try {
			connection = getConnection();
		} catch (Exception e) {
			e.printStackTrace();
		}
		this.container = container;
	}

	/**
	 * Zum Löschen eines Trackers muss seine Tracker-ID übergeben werden. Beim
	 * Erstellen eines Trackers kann für die Tracker-ID null übergeben werden.
	 * 
	 * Dieser Konstruktor dient dazu, einen Tracker von einem Dialog aus zu
	 * löschen!
	 * 
	 * @param action
	 * @param progressBar
	 * @param id
	 * @param container
	 *            der Dialog
	 */
	public TrackerVerwaltenThread(TrackerVerwaltungAction action,
			JProgressBar progressBar, String id, JDialog container) {
		super();
		this.action = action;
		this.progressBar = progressBar;
		this.id = id;
		try {
			connection = getConnection();
		} catch (Exception e) {
			e.printStackTrace();
		}
		this.dialog = container;
	}

	@Override
	public void run() {
		if (action.equals(TrackerVerwaltungAction.TRACKER_LÖSCHEN))
			deleteTracker(id);
		else if (action.equals(TrackerVerwaltungAction.TRACKER_ERSTELLEN))
			createTracker();
		else if (action.equals(TrackerVerwaltungAction.TRACKER_EINTRAGEN))
			enterTracker();
	}

	@Override
	public Connection getConnection() throws Exception {
		Connection connection;
		Class.forName("com.mysql.jdbc.Driver");
		connection = DriverManager.getConnection(DB_CONNECTION_URL,
				DB_USERNAME, DB_PASSWORD);
		return connection;
	}

	@Override
	public ResultSet executeStatementOnDB(String stmnt) throws Exception {
		Statement statement = connection.createStatement();
		if (action.equals(TrackerVerwaltungAction.TRACKER_LÖSCHEN)) {
			statement.execute(stmnt);
			return null;
		} else {
			try {
				statement.executeUpdate(stmnt, Statement.RETURN_GENERATED_KEYS);
			} catch (MySQLIntegrityConstraintViolationException e) {
				// ID im Insert existiert bereits!
				return null;
			}
			return statement.getGeneratedKeys();
		}
	}

	/**
	 * Löscht den Tracker mit der übergebenen ID.
	 * 
	 * @param id
	 *            Tracker-ID
	 */
	private void deleteTracker(String id) {
		String delete = "delete from tracker where id=\"" + id + "\";";
		try {
			executeStatementOnDB(delete);
		} catch (Exception e) {
			e.printStackTrace();
		}
		// Trucker aus XML löschen.
		leseTrackerAusXML();
		trackerListe.remove(id);
		schreibeTrackerInXML();
		// Lade-Balken stoppen
		progressBar.setIndeterminate(false);
		if (container != null)
			container.setCursor(Cursor
					.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		if (dialog != null)
			dialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
	}

	/**
	 * Erstellt einen neuen Tracker in der Datenbank.
	 */
	private void createTracker() {
		tracker = new Tracker(id, Long.toString(generatePassword()));

		String md5PW = md5(tracker.getPasswort());
		System.out.println(md5PW);
		String insert = "insert into tracker values(0,\"" + md5PW + "\",0);";
		try {
			ResultSet result = executeStatementOnDB(insert);
			result.next();
			tracker.setId(Integer.toString(result.getInt(1)));
		} catch (Exception e) {
			e.printStackTrace();
		}
		progressBar.setIndeterminate(false);
		container.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		createTrackerCreateDialog();
	}

	/**
	 * Trägt einen Tracker mit uebergebener ID in die Datenbank ein.
	 */
	private void enterTracker() {
		tracker = new Tracker(id, Long.toString(generatePassword()));

		String md5PW = md5(tracker.getPasswort());

		String insert = "insert into tracker values(" + id + ",\"" + md5PW
				+ "\",0);";
		try {
			ResultSet rs = executeStatementOnDB(insert);
			if (rs == null) {
				JOptionPane.showMessageDialog(container,
						"Eingegebene Trucker-ID existiert bereits!", "Fehler!",
						JOptionPane.ERROR_MESSAGE);
				progressBar.setIndeterminate(false);
				container.setCursor(Cursor
						.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
				return;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		progressBar.setIndeterminate(false);
		container.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		createTrackerCreateDialog();
	}

	/**
	 * Generiert ein Passwort
	 * 
	 * @return das Passwort
	 */
	long generatePassword() {
		Random rand = new Random();
		long pw = Math.abs(rand.nextLong());
		return pw;
	}

	/**
	 * Zeigt den Informationen zum Erstellten Tracker in einem Dialog an.
	 */
	private void createTrackerCreateDialog() {
		JPanel panel = new JPanel(new GridLayout(10, 1));
		final JTextArea label = new JTextArea("Trucker-ID:\t" + tracker.getId()
				+ "\nPasswort:\t" + tracker.getPasswort());
		label.setEditable(false);
		final JTextField email = new JTextField();
		PromptSupport.setPrompt("E-Mail Adresse", email);
		final JTextField vorname = new JTextField();
		PromptSupport.setPrompt("Vorname", vorname);
		final JTextField nachname = new JTextField();
		PromptSupport.setPrompt("Nachname", nachname);
		final JTextField wohnort = new JTextField();
		PromptSupport.setPrompt("Wohnort", wohnort);
		final JTextField strasse = new JTextField();
		PromptSupport.setPrompt("Straße + Nr.", strasse);
		final JTextField telefonnummer = new JTextField();
		PromptSupport.setPrompt("Telefonnummer", telefonnummer);
		final JTextField plz = new JTextField();
		PromptSupport.setPrompt("PLZ", plz);

		final JButton speichern = new JButton("Speichern");
		speichern.setEnabled(false);
		JButton emailSenden = new JButton("E-Mail an Trucker");

		panel.add(label);
		panel.add(email);
		panel.add(vorname);
		panel.add(nachname);
		panel.add(wohnort);
		panel.add(plz);
		panel.add(strasse);
		panel.add(telefonnummer);
		panel.add(emailSenden);
		panel.add(speichern);

		label.setBackground(Color.WHITE);

		final JPopupMenu rechtsKlick = new JPopupMenu();
		JMenuItem item = new JMenuItem("Kopieren");
		item.setMnemonic(KeyEvent.VK_C);
		rechtsKlick.add(item);

		item.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				label.copy();
			}
		});

		label.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				if (e.getButton() == MouseEvent.BUTTON3)
					rechtsKlick.show(label, 20, 20);
			}
		});

		final JDialog dialog = new JDialog();
		dialog.setBounds(container.getX() + 100, container.getY() + 50, 600,
				500);
		dialog.add(panel);
		dialog.setTitle("Trucker generieren");
		dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
		dialog.setVisible(true);

		emailSenden.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				if (email.getText().length() == 0)
					JOptionPane.showConfirmDialog(dialog,
							"Keine E-Mail Adresse eingetragen!", "Fehler!",
							JOptionPane.ERROR_MESSAGE);
				else {
					try {
						// Charset UTF-8 oder ISO-8859-1
						URI uri = new URI(
								URIUtil.encodeQuery(
										"mailto:"
												+ email.getText()
												+ "?subject="
												+ EMAIL_SUBJECT
												+ "&body=Hallo "
												+ vorname.getText()
												+ " "
												+ nachname.getText()
												+ ",\n\nSie sind nun als Trucker bei Radio2000 registriert und können die VerkehrsInfo-App auch zum Aufgeben von Meldungen nutzen!\n\nIhre Login-Daten für die App sind:\n\nTrucker-ID:\t"
												+ tracker.getId()
												+ "\nPasswort:\t"
												+ tracker.getPasswort()
												+ "\n\nWir wünschen viel Spaß beim Verwenden der App!\n\nMit freundlichen Grüßen,\ndas Radio2000-Team",
										"ISO-8859-1"));
						try {
							Desktop.getDesktop().mail(uri);
						} catch (IOException e1) {
							// TODO Auto-generated catch block
							e1.printStackTrace();
						}
					} catch (URISyntaxException e2) {
						// TODO Auto-generated catch block
						e2.printStackTrace();
					} catch (URIException e2) {
						// TODO Auto-generated catch block
						e2.printStackTrace();
					}
					speichern.setEnabled(true);
				}
			}
		});

		speichern.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				if (vorname.getText().length() != 0
						&& nachname.getText().length() != 0
						&& email.getText().length() != 0
						&& wohnort.getText().length() != 0) {
					leseTrackerAusXML();
					Tracker t = new Tracker(tracker.getId(), vorname.getText(),
							nachname.getText(), email.getText(), telefonnummer
									.getText(), new Adresse(wohnort.getText(),
									strasse.getText(), plz.getText()));
					trackerListe.put(tracker.getId(), t);
					schreibeTrackerInXML();
					dialog.dispose();
				} else {
					JOptionPane.showMessageDialog(dialog,
							"Alle Eingabefelder müssen gefüllt sein!",
							"Achtung!", JOptionPane.ERROR_MESSAGE);
				}
			}
		});
	}

	public Tracker getTracker() {
		return tracker;
	}

	/**
	 * Speichert alle Tracker aus der XML-Datei in die Tracker-Liste.
	 */
	private void leseTrackerAusXML() {
		try {
			JAXBContext context = JAXBContext.newInstance(TrackerList.class);
			Unmarshaller unM = context.createUnmarshaller();
			TrackerList list = (TrackerList) unM.unmarshal(new FileReader(
					new File(GUI.XML_FILENAME)));
			trackerListe = list.trackerListe;
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (JAXBException e) {
			// XML-Datei noch leer!
			trackerListe = new HashMap<String, Tracker>();
		}
	}

	/**
	 * Speichert alle Tracker aus der Tracker-Liste in die XML-Datei. (nur wenn
	 * die TrackerListe schon Einträge enthält)
	 */
	private void schreibeTrackerInXML() {
		if (trackerListe != null) {
			try {
				JAXBContext context = JAXBContext
						.newInstance(TrackerList.class);
				Marshaller m = context.createMarshaller();
				m.marshal(new TrackerList(trackerListe), new FileWriter(
						new File(GUI.XML_FILENAME)));
			} catch (JAXBException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	/**
	 * Generiert einen MD5-Schluessel aus dem input
	 * 
	 * @param input
	 * @return
	 * @throws NoSuchAlgorithmException
	 */
	public static String md5(String input) {
		String result = input;
		if (input != null) {
			MessageDigest md = null;
			try {
				md = MessageDigest.getInstance("MD5");
			} catch (NoSuchAlgorithmException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			md.update(input.getBytes());
			BigInteger hash = new BigInteger(1, md.digest());
			result = hash.toString(16);
			while (result.length() < 32) {
				result = "0" + result;
			}
		}
		return result;
	}

}
